﻿// ----------------------------------------------------------------------------
// stdinteger.h 
// ----------------------------------------------------------------------------
/*
 Description :
 各機種で共通して利用可能な stdint.h
 古いVisualStudio等で動作をさせるためのワークアラウンドになっている.
 存在しない場合は独自の定義を行う. 
 
 名前の衝突を防ぐために fw 名前空間で型を定義しているが、
 利用するときはfw名前空間をつけないでください.
 */
#pragma once
#include <fw/base/core/macros.h>

#if USING(FW_COMPILER_MSC) || USING(FW_COMPILER_MSVC)
#if _MSC_VER < 1600
#ifndef __HOST_STDINT_H__
#define __HOST_STDINT_H__
#ifdef __cplusplus
namespace fw
{
#endif /* __cplusplus */
    typedef signed char       int8_t;
    typedef unsigned char     uint8_t;
    typedef signed char       int_least8_t;
    typedef unsigned char     uint_least8_t;
    typedef signed char       int_fast8_t;
    typedef unsigned char     uint_fast8_t;
    
    typedef signed short      int16_t;
    typedef unsigned short    uint16_t;
    typedef signed short      int_least16_t;
    typedef unsigned short    uint_least16_t;
    typedef signed short      int_fast16_t;
    typedef unsigned short    uint_fast16_t;
    
    typedef signed int        int32_t;
    typedef unsigned int      uint32_t;
    typedef signed int        int_least32_t;
    typedef unsigned int      uint_least32_t;
    typedef signed int        int_fast32_t;
    typedef unsigned int      uint_fast32_t;
    
    typedef signed __int64    int64_t;
    typedef unsigned __int64  uint64_t;
    typedef signed __int64    int_least64_t;
    typedef unsigned __int64  uint_least64_t;
    typedef signed __int64    int_fast64_t;
    typedef unsigned __int64  uint_fast64_t;
    
#ifdef __cplusplus
} // namespace fw 

using ::fw::int8_t;
using ::fw::uint8_t;
using ::fw::int_least8_t;
using ::fw::uint_least8_t;
using ::fw::int_fast8_t;
using ::fw::uint_fast8_t;

using ::fw::int16_t;
using ::fw::uint16_t;
using ::fw::int_least16_t;
using ::fw::uint_least16_t;
using ::fw::int_fast16_t;
using ::fw::uint_fast16_t;

using ::fw::int32_t;
using ::fw::uint32_t;
using ::fw::int_least32_t;
using ::fw::uint_least32_t;
using ::fw::int_fast32_t;
using ::fw::uint_fast32_t;

using ::fw::int64_t;
using ::fw::uint64_t;
using ::fw::int_least64_t;
using ::fw::uint_least64_t;
using ::fw::int_fast64_t;
using ::fw::uint_fast64_t;

#endif /* __cplusplus */

#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS)

#define INT8_MIN          -128
#define INT8_MAX          127
#define UINT8_MAX         255

#define INT_LEAST8_MIN    -128
#define INT_LEAST8_MAX    127
#define UINT_LEAST8_MAX   255

#define INT_FAST8_MIN     -128
#define INT_FAST8_MAX     127
#define UINT_FAST8_MAX    255

#define INT16_MIN         -32768
#define INT16_MAX         32767
#define UINT16_MAX        65535

#define INT_LEAST16_MIN   -32768
#define INT_LEAST16_MAX   32767
#define UINT_LEAST16_MAX  65535

#define INT_FAST16_MIN    -32768
#define INT_FAST16_MAX    32767
#define UINT_FAST16_MAX   65535

#define INT32_MIN         (-2147483647-1)
#define INT32_MAX         2147483647
#define UINT32_MAX        0xffffffff

#define INT_LEAST32_MIN   (-2147483647-1)
#define INT_LEAST32_MAX   2147483647
#define UINT_LEAST32_MAX  0xffffffff

#define INT_FAST32_MIN    (-2147483647-1)
#define INT_FAST32_MAX    2147483647
#define UINT_FAST32_MAX   0xffffffff

#define INT64_MIN         (-9223372036854775807-1)
#define INT64_MAX         9223372036854775807
#define UINT64_MAX        0xffffffffffffffff

#define INT_LEAST64_MIN   (-9223372036854775807-1)
#define INT_LEAST64_MAX   9223372036854775807
#define UINT_LEAST64_MAX  0xffffffffffffffff

#define INT_FAST64_MIN    (-9223372036854775807i64-1)
#define INT_FAST64_MAX    9223372036854775807i64
#define UINT_FAST64_MAX   0xffffffffffffffffui64

#endif /* !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) */

#endif // __HOST_STDINT_H__
#else
#include <stdint.h>		// MSVC 2010 supports stdint.h
#endif // MSVC 2008 or older. 
#else
#include <stdint.h>
#endif // FW_COMPILER_MSC || FW_COMPILER_MSVC


namespace fw
{
	//---------------------------------------------------------------
	// 32bit instructions.
	
	FW_FORCE_INLINE uint32_t uint32_li		(uint32_t v)
	{
		return v;
	}
	
	FW_FORCE_INLINE uint32_t uint32_dec		(uint32_t v)
	{
		return v - 1;
	}
	
	FW_FORCE_INLINE uint32_t uint32_inc		(uint32_t v)
	{
		return v + 1;
	}

	FW_FORCE_INLINE uint32_t uint32_not		(uint32_t v)
	{
		return ~v;
	}

	FW_FORCE_INLINE uint32_t uint32_neg		(uint32_t v)
	{
		return -static_cast<int32_t>(v);
	}

	FW_FORCE_INLINE uint32_t uint32_ext		(uint32_t v)
	{
		return (static_cast<int32_t>(v)) >> 31;
	}

	FW_FORCE_INLINE uint32_t uint32_and		(uint32_t a, uint32_t b)
	{
		return a & b;
	}

	FW_FORCE_INLINE uint32_t uint32_xor		(uint32_t a, uint32_t b)
	{
		return a ^ b;
	}

	FW_FORCE_INLINE uint32_t uint32_xorl	(uint32_t a, uint32_t b)
	{
		return !a != !b;
	}

	FW_FORCE_INLINE uint32_t uint32_andc	(uint32_t a, uint32_t b)
	{
		return a & ~b;
	}

	FW_FORCE_INLINE uint32_t uint32_or		(uint32_t a, uint32_t b)
	{
		return a | b;
	}

	FW_FORCE_INLINE uint32_t uint32_sll		(uint32_t a, uint32_t b)
	{
		return a << b;
	}

	FW_FORCE_INLINE uint32_t uint32_srl		(uint32_t a, uint32_t b)
	{
		return a >> b;
	}

	FW_FORCE_INLINE uint32_t uint32_sra		(uint32_t a, uint32_t b)
	{
		return static_cast<int32_t>(a) >> b;
	}
	
	FW_FORCE_INLINE uint32_t uint32_rol		(uint32_t a, uint32_t b)
	{
		return ( a << b ) | ( a >> (32 - b));
	}
	
	FW_FORCE_INLINE uint32_t uint32_ror		(uint32_t a, uint32_t b)
	{
		return ( a >> b ) | ( a << (32 - b));
	}

	FW_FORCE_INLINE uint32_t uint32_add		(uint32_t a, uint32_t b)
	{
		return a + b;
	}
	
	FW_FORCE_INLINE uint32_t uint32_sub		(uint32_t a, uint32_t b)
	{
		return a - b;
	}

	FW_FORCE_INLINE uint32_t uint32_mul		(uint32_t a, uint32_t b)
	{
		return a * b;
	}

	FW_FORCE_INLINE uint32_t uint32_div		(uint32_t a, uint32_t b)
	{
		return a / b;
	}

	FW_FORCE_INLINE uint32_t uint32_mod		(uint32_t a, uint32_t b)
	{
		return a % b;
	}

	FW_FORCE_INLINE uint32_t uint32_cmpeq	(uint32_t a, uint32_t b)
	{
		return -( a == b);
	}

	FW_FORCE_INLINE uint32_t uint32_cmpneq	(uint32_t a, uint32_t b)
	{
		return -( a != b);
	}

	FW_FORCE_INLINE uint32_t uint32_cmplt	(uint32_t a, uint32_t b)
	{
		return -( a < b);
	}
	
	FW_FORCE_INLINE uint32_t uint32_cmple	(uint32_t a, uint32_t b)
	{
		return -( a <= b);
	}

	FW_FORCE_INLINE uint32_t uint32_cmpgt	(uint32_t a, uint32_t b)
	{
		return -( a > b);
	}
	
	FW_FORCE_INLINE uint32_t uint32_cmpge	(uint32_t a, uint32_t b)
	{
		return -( a >= b);
	}

	FW_FORCE_INLINE uint32_t uint32_setnz	(uint32_t a)
	{
		return -!!a;
	}

	FW_FORCE_INLINE uint32_t uint32_satadd	(uint32_t a, uint32_t b)
	{
		const uint32_t add		= uint32_add  (a, b);
		const uint32_t lt		= uint32_cmplt(add, a);
		const uint32_t result	= uint32_or	  (add, lt);
		
		return result;
	}

	FW_FORCE_INLINE uint32_t uint32_satsub	(uint32_t a, uint32_t b)
	{
		const uint32_t sub		= uint32_sub  (a, b);
		const uint32_t le		= uint32_cmple(sub, a);
		const uint32_t result	= uint32_and  (sub, le);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_satmul	(uint32_t a, uint32_t b)
	{
		const uint64_t mul		= static_cast<uint64_t>(a) * static_cast<uint64_t>(b);
		const uint32_t hi		= mul >> 32;
		const uint32_t nz		= uint32_setnz(hi);
		const uint32_t result	= uint32_or(static_cast<uint32_t>(mul), nz);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_sels	(uint32_t test, uint32_t a, uint32_t b)
	{	// select by sign.
		const uint32_t mask		= uint32_ext(test);
		const uint32_t sel_a	= uint32_and(a, mask);
		const uint32_t sel_b	= uint32_andc(b, mask);
		const uint32_t result	= uint32_or(sel_a, sel_b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_selb	(uint32_t mask, uint32_t a, uint32_t b)
	{	// select by bitmask.
		const uint32_t sel_a	= uint32_and(a, mask);
		const uint32_t sel_b	= uint32_andc(b, mask);
		const uint32_t result	= uint32_or(sel_a, sel_b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_imin	(uint32_t a, uint32_t b)
	{
		const uint32_t a_sub_b = uint32_sub(a, b);
		const uint32_t result  = uint32_sels(a_sub_b, a, b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_imax	(uint32_t a, uint32_t b)
	{
		const uint32_t b_sub_a = uint32_sub(b, a);
		const uint32_t result  = uint32_sels(b_sub_a, a, b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_min		(uint32_t a, uint32_t b)
	{
		return a > b ? b : a;
	}
	
	FW_FORCE_INLINE uint32_t uint32_max		(uint32_t a, uint32_t b)
	{
		return a > b ? a : b;
	}

	FW_FORCE_INLINE uint32_t uint32_incwrap	(uint32_t val, uint32_t min, uint32_t max)
	{
		const uint32_t inc          = uint32_inc(val);
		const uint32_t max_diff     = uint32_sub(max, val);
		const uint32_t neg_max_diff = uint32_neg(max_diff);
		const uint32_t max_or       = uint32_or(max_diff, neg_max_diff);
		const uint32_t max_diff_nz  = uint32_ext(max_or);
		const uint32_t result       = uint32_selb(max_diff_nz, inc, min);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_decwrap	(uint32_t val, uint32_t min, uint32_t max)
	{
		const uint32_t dec          = uint32_dec(val);
		const uint32_t min_diff     = uint32_sub(min, val);
		const uint32_t neg_min_diff = uint32_neg(min_diff);
		const uint32_t min_or       = uint32_or(min_diff, neg_min_diff);
		const uint32_t min_diff_nz  = uint32_ext(min_or);
		const uint32_t result       = uint32_selb(min_diff_nz, dec, max);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_cntbits_ref(uint32_t val)
	{
		const uint32_t tmp0   = uint32_srl(val, 1);
		const uint32_t tmp1   = uint32_and(tmp0, 0x55555555);
		const uint32_t tmp2   = uint32_sub(val, tmp1);
		const uint32_t tmp3   = uint32_and(tmp2, 0xc30c30c3);
		const uint32_t tmp4   = uint32_srl(tmp2, 2);
		const uint32_t tmp5   = uint32_and(tmp4, 0xc30c30c3);
		const uint32_t tmp6   = uint32_srl(tmp2, 4);
		const uint32_t tmp7   = uint32_and(tmp6, 0xc30c30c3);
		const uint32_t tmp8   = uint32_add(tmp3, tmp5);
		const uint32_t tmp9   = uint32_add(tmp7, tmp8);
		const uint32_t tmpA   = uint32_srl(tmp9, 6);
		const uint32_t tmpB   = uint32_add(tmp9, tmpA);
		const uint32_t tmpC   = uint32_srl(tmpB, 12);
		const uint32_t tmpD   = uint32_srl(tmpB, 24);
		const uint32_t tmpE   = uint32_add(tmpB, tmpC);
		const uint32_t tmpF   = uint32_add(tmpD, tmpE);
		const uint32_t result = uint32_and(tmpF, 0x3f);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_cntbits	(uint32_t val)
	{
	#if   USING(FW_COMPILER_GCC) || USING(FW_COMPILER_CLANG)
		return __builtin_popcount(val);
	#elif USING(FW_COMPILER_MSVC)|| USING(FW_COMPILER_MSC)
		return __popcnt(val);
	#else
		return uint32_cntbits_ref(val);
	#endif
	}
	
	FW_FORCE_INLINE uint32_t uint32_cntlz_ref(uint32_t val)
	{
		const uint32_t tmp0   = uint32_srl(val, 1);
		const uint32_t tmp1   = uint32_or(tmp0, val);
		const uint32_t tmp2   = uint32_srl(tmp1, 2);
		const uint32_t tmp3   = uint32_or(tmp2, tmp1);
		const uint32_t tmp4   = uint32_srl(tmp3, 4);
		const uint32_t tmp5   = uint32_or(tmp4, tmp3);
		const uint32_t tmp6   = uint32_srl(tmp5, 8);
		const uint32_t tmp7   = uint32_or(tmp6, tmp5);
		const uint32_t tmp8   = uint32_srl(tmp7, 16);
		const uint32_t tmp9   = uint32_or(tmp8, tmp7);
		const uint32_t tmpA   = uint32_not(tmp9);
		const uint32_t result = uint32_cntbits(tmpA);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_cntlz	(uint32_t val)
	{
	#if   USING(FW_COMPILER_GCC) || USING(FW_COMPILER_CLANG)
		return __builtin_clz(val);
	#elif USING(FW_COMPILER_MSVC)|| USING(FW_COMPILER_MSC)
		unsigned long index;
		_BitScanReverse(&index, val);
		return 31 - index;
	#else
		return uint32_cntlz_ref(val);
	#endif
	}
	
	FW_FORCE_INLINE uint32_t uint32_shuffleA(uint32_t a)
	{	// 0xffff -> 0x55555555
		const uint32_t val    = uint32_and(a, 0xffff);
		
		const uint32_t tmp0   = uint32_sll(val, 8);
		const uint32_t tmp1   = uint32_xor(val, tmp0);
		const uint32_t tmp2   = uint32_and(tmp1, 0x00ff00ff);
		
		const uint32_t tmp3   = uint32_sll(tmp2, 4);
		const uint32_t tmp4   = uint32_xor(tmp2, tmp3);
		const uint32_t tmp5   = uint32_and(tmp4, 0x0f0f0f0f);
		
		const uint32_t tmp6   = uint32_sll(tmp5, 2);
		const uint32_t tmp7   = uint32_xor(tmp5, tmp6);
		const uint32_t tmp8   = uint32_and(tmp7, 0x33333333);
		
		const uint32_t tmp9   = uint32_sll(tmp8, 1);
		const uint32_t tmpA   = uint32_xor(tmp8, tmp9);
		const uint32_t result = uint32_and(tmpA, 0x55555555);
		
		return result;
	}
	
	FW_FORCE_INLINE uint32_t uint32_shuffleB(uint32_t a)
	{	// 0x03ff -> 0x09249249
		const uint32_t val    = uint32_and(a, 0x3ff);
		
		const uint32_t tmp0   = uint32_sll(val, 16);
		const uint32_t tmp1   = uint32_xor(val, tmp0);
		const uint32_t tmp2   = uint32_and(tmp1, 0xff0000ff);
		
		const uint32_t tmp3   = uint32_sll(tmp2, 8);
		const uint32_t tmp4   = uint32_xor(tmp2, tmp3);
		const uint32_t tmp5   = uint32_and(tmp4, 0x0300f00f);
		
		const uint32_t tmp6   = uint32_sll(tmp5, 4);
		const uint32_t tmp7   = uint32_xor(tmp5, tmp6);
		const uint32_t tmp8   = uint32_and(tmp7, 0x030c30c3);
		
		const uint32_t tmp9   = uint32_sll(tmp8, 2);
		const uint32_t tmpA   = uint32_xor(tmp8, tmp9);
		const uint32_t result = uint32_and(tmpA, 0x09249249);
		
		return result;
	}

	//---------------------------------------------------------------
	// 64bit instructions.
	
	
	FW_FORCE_INLINE uint64_t uint64_li		(uint64_t v)
	{
		return v;
	}
	
	FW_FORCE_INLINE uint64_t uint64_dec		(uint64_t v)
	{
		return v - 1;
	}
	
	FW_FORCE_INLINE uint64_t uint64_inc		(uint64_t v)
	{
		return v + 1;
	}
	
	FW_FORCE_INLINE uint64_t uint64_not		(uint64_t v)
	{
		return ~v;
	}

	FW_FORCE_INLINE uint64_t uint64_neg		(uint64_t v)
	{
		return -static_cast<int32_t>(v);
	}
	
	FW_FORCE_INLINE uint64_t uint64_ext		(uint64_t v)
	{
		return (static_cast<int32_t>(v)) >> 31;
	}
	
	FW_FORCE_INLINE uint64_t uint64_and		(uint64_t a, uint64_t b)
	{
		return a & b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_xor		(uint64_t a, uint64_t b)
	{
		return a ^ b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_xorl	(uint64_t a, uint64_t b)
	{
		return !a != !b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_andc	(uint64_t a, uint64_t b)
	{
		return a & ~b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_or		(uint64_t a, uint64_t b)
	{
		return a | b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_sll		(uint64_t a, uint64_t b)
	{
		return a << b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_srl		(uint64_t a, uint64_t b)
	{
		return a >> b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_sra		(uint64_t a, uint64_t b)
	{
		return static_cast<int64_t>(a) >> b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_rol		(uint64_t a, uint64_t b)
	{
		return ( a << b ) | ( a >> (32 - b));
	}
	
	FW_FORCE_INLINE uint64_t uint64_ror		(uint64_t a, uint64_t b)
	{
		return ( a >> b ) | ( a << (32 - b));
	}
	
	FW_FORCE_INLINE uint64_t uint64_add		(uint64_t a, uint64_t b)
	{
		return a + b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_sub		(uint64_t a, uint64_t b)
	{
		return a - b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_mul		(uint64_t a, uint64_t b)
	{
		return a * b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_div		(uint64_t a, uint64_t b)
	{
		return a / b;
	}

	FW_FORCE_INLINE uint64_t uint64_mod		(uint64_t a, uint64_t b)
	{
		return a % b;
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmpeq	(uint64_t a, uint64_t b)
	{
		return -( a == b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmpneq	(uint64_t a, uint64_t b)
	{
		return -( a != b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmplt	(uint64_t a, uint64_t b)
	{
		return -( a < b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmple	(uint64_t a, uint64_t b)
	{
		return -( a <= b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmpgt	(uint64_t a, uint64_t b)
	{
		return -( a > b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_cmpge	(uint64_t a, uint64_t b)
	{
		return -( a >= b);
	}
	
	FW_FORCE_INLINE uint64_t uint64_setnz	(uint64_t a)
	{
		return -!!a;
	}

	FW_FORCE_INLINE uint64_t uint64_satadd	(uint64_t a, uint64_t b)
	{
		const uint64_t add		= uint64_add  (a, b);
		const uint64_t lt		= uint64_cmplt(add, a);
		const uint64_t result	= uint64_or	  (add, lt);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_satsub	(uint64_t a, uint64_t b)
	{
		const uint64_t sub		= uint64_sub  (a, b);
		const uint64_t le		= uint64_cmple(sub, a);
		const uint64_t result	= uint64_and  (sub, le);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_sels	(uint64_t test, uint64_t a, uint64_t b)
	{	// select by sign.
		const uint64_t mask		= uint64_ext(test);
		const uint64_t sel_a	= uint64_and(a, mask);
		const uint64_t sel_b	= uint64_andc(b, mask);
		const uint64_t result	= uint64_or(sel_a, sel_b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_selb	(uint64_t mask, uint64_t a, uint64_t b)
	{	// select by bitmask.
		const uint64_t sel_a	= uint64_and(a, mask);
		const uint64_t sel_b	= uint64_andc(b, mask);
		const uint64_t result	= uint64_or(sel_a, sel_b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_imin	(uint64_t a, uint64_t b)
	{
		const uint64_t a_sub_b = uint64_sub(a, b);
		const uint64_t result  = uint64_sels(a_sub_b, a, b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_imax	(uint64_t a, uint64_t b)
	{
		const uint64_t b_sub_a = uint64_sub(b, a);
		const uint64_t result  = uint64_sels(b_sub_a, a, b);
		
		return result;
	}
	
	FW_FORCE_INLINE uint64_t uint64_min		(uint64_t a, uint64_t b)
	{
		return a > b ? b : a;
	}
	
	FW_FORCE_INLINE uint64_t uint64_max		(uint64_t a, uint64_t b)
	{
		return a > b ? a : b;
	}

} // namespace fw

